

pub fn get_numbers(line: &str) -> Vec<i64> {
    let mut numbers: Vec<i64> = Vec::new();
    for token in line.split(" ") {
        let token = token.trim();
        if token.is_empty() {
            continue;
        }
        numbers.push(token.parse().unwrap());
    }
    numbers
}

pub fn extrapolate_numbers(numbers: Vec<i64>) -> Vec<Vec<i64>> {
    let mut result: Vec<Vec<i64>> = Vec::new();
    result.push(numbers);

    loop {
        let numbers = result.last().unwrap();
        let mut new_numbers: Vec<i64> = Vec::new();
        for (i, &number) in numbers.iter().rev().skip(1).rev().enumerate() {
            new_numbers.push(numbers.get(i + 1).unwrap().clone() - number);
        }

        let mut end = true;
        for &number in new_numbers.iter() {
            if number != 0 {
                end = false;
                break;
            }
        }

        result.push(new_numbers);
        if end {
            return result;
        }
    }
}

pub fn get_history_part1(result: Vec<Vec<i64>>) -> i64 {
    let mut history: i64 = 0;
    for numbers in result.iter().rev().skip(1) {
        history += numbers.last().unwrap();
    }
    history
}

pub fn get_history_part2(result: Vec<Vec<i64>>) -> i64 {
    let mut history: i64 = 0;
    for numbers in result.iter().rev().skip(1) {
        history = numbers.first().unwrap() - history;
    }
    history
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_get_numbers() {
        let numbers = get_numbers("0 3 6 9 12 15");
        assert_eq!(
            numbers,
            vec![0, 3, 6, 9, 12, 15]
        );
    }

    #[test]
    fn test_extrapolate_numbers() {
        let res = extrapolate_numbers(vec![0, 3, 6, 9, 12, 15]);
        assert_eq!(
            res,
            vec![
                vec![0, 3, 6, 9, 12, 15],
                vec![3, 3, 3, 3, 3],
                vec![0, 0, 0, 0]
            ]
        );
    }

    #[test]
    fn test_get_history() {
        let res = extrapolate_numbers(vec![0, 3, 6, 9, 12, 15]);
        let history = get_history_part1(res);
        assert_eq!(history, 18);
    }
}